package com.sychip.fhc.app.wsn.screen

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.text.Html
import androidx.compose.runtime.mutableStateListOf
import androidx.core.content.FileProvider
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.fhc.base.Async
import com.fhc.base.EventType
import com.fhc.base.FhcFlowEventBus
import com.fhc.base.FlowEventBusData
import com.fhc.base.minMax
import com.fhc.base.ymdHMS
import com.fhc.excel.createExcel
import com.fhc.view.sound.SoundPoolPlayer
import com.fhc.view.sound.SoundType
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.sychip.fhc.MainApplication
import com.sychip.fhc.app.data.repo.WsnDeviceRepo
import com.sychip.fhc.app.data.repo.WsnDeviceRssiRepo
import com.sychip.fhc.app.data.repo.WsnTestRecordRepo
import com.sychip.fhc.app.data.source.dto.WsnDeviceRssiDto
import com.sychip.fhc.app.data.source.dto.WsnTestRecordDto
import com.sychip.fhc.app.pref.AppSetting
import com.sychip.fhc.app.pref.PrefDataStoreIf
import com.sychip.fhc.app.todo.R
import com.sychip.fhc.app.wsn.common.RssiInterval
import com.sychip.fhc.app.wsn.nav.NAV_JSON_ARG
import com.sychip.fhc.app.wsn.nav.PostToWsnDetail
import com.sychip.fhc.base.BaseAppViewModel
import com.sychip.fhc.base.UiDataState
import com.sychip.fhc.di.DefaultDispatcher
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted.Companion.Eagerly
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
import java.util.Locale
import javax.inject.Inject
import kotlin.math.floor

/**
 * Wsn rssi detail view model
 *
 * @property devRepo
 * @property rssiRepo
 * @property appScope
 * @property dispatcher
 * @constructor
 *
 * @param savedStateHandle
 * @param app
 */
@HiltViewModel
class WsnRssiDetailViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    app : MainApplication,
    private val prefDataStore: PrefDataStoreIf,
    private val devRepo: WsnDeviceRepo,
    private val rssiRepo: WsnDeviceRssiRepo,
    private val testRepo: WsnTestRecordRepo,
    @DefaultDispatcher private val dispatcher: CoroutineDispatcher,
) : BaseAppViewModel(app, prefDataStore) {


    private var _rssiData : MutableList<WsnDeviceRssiDto>  =  mutableStateListOf()
//    @ApplicationScope private val appScope: CoroutineScope,
//    ViewModel 的职责是管理与 UI 相关的数据和逻辑，不应该去控制整个应用程序级别的资源（如全局协程作用域）。这种做法会破坏模块间的解耦性。
    private var isPlaying = false
    private var repeatJob: Job? = null
    private var avgJob: Job? = null
    private var perJob: Job? = null


    private val soundPlayer = SoundPoolPlayer(application = app)
    fun startRepeatingSound() {
        isPlaying = true
        repeatJob?.cancel()
        repeatJob = viewModelScope.launch {
            while (isPlaying) {
                soundPlayer.play(SoundType.TimerOver)
                delay(3000L)
            }
        }
    }

    fun stopRepeatingSound() {
        soundPlayer.release()
        isPlaying = false
        repeatJob?.cancel()
    }

    fun startAvgPerJob() {
        isPlaying = true
        avgJob?.cancel()
        perJob?.cancel()
        avgJob =   viewModelScope.launch {
            while (isActive) {
                calcRssiAvg()
                delay(if(_perSecs.value < 0) RssiInterval else RssiInterval/4 )  //仅仅为了一开始rssi avg能及时显示而已，因为rssi avg原本按照上报立即计算的
            }
        }
        perJob =  viewModelScope.launch {
            while (isActive) {
                calcRssiPer()
                delay(RssiInterval  )
            }
        }
    }

    private val _uiDataState = MutableStateFlow(UiDataState())


    // 从 SavedStateHandle 获取参数
    private val  navJsonArg: String = savedStateHandle[NAV_JSON_ARG]?: ""
    private val params = navJsonArg.let { json ->
        Moshi.Builder().add(KotlinJsonAdapterFactory()).build().adapter(PostToWsnDetail::class.java).lenient().fromJson(json)
    }
    private var fromDevId: String = params?.fromDevId ?: ""
    private var toDevId: String =  params?.toDevId?: ""
    private var fromTime: Long =  params?.fromTime?: 0L
    private var toTime: Long =  params?.toTime?: 0L

    private val isHistory: Boolean = fromTime == 0L && toTime == 0L

    var testFromTime :Long = System.currentTimeMillis()


    private var _rssiList : MutableList<WsnDeviceRssiDto>  =  mutableStateListOf()

//    private var currentTestRecord:WsnTestRecordDto = WsnTestRecordDto(usbId = "", fromTime = fromTime)


    private val _appSettingFlow = MutableStateFlow<AppSetting>(AppSetting())
    val appSettingFlow: StateFlow<AppSetting> = _appSettingFlow.asStateFlow()
    private val _perSecs = MutableStateFlow(12.0f)
    val perSecs: StateFlow<Float> = _perSecs.asStateFlow()

    private var countdownJob: Job? = null
    private fun startCountdown() {
        // 如果已有倒计时在运行，则先取消它
        countdownJob?.cancel()
        countdownJob = viewModelScope.launch {
            while (isActive) {
                delay(1000L) // 每秒触发
                _perSecs.update { it - 1f }
                if(_perSecs.value < 0){
//                    startRepeatingSound()
                    return@launch
                }
            }
        }
    }
    private var rssiDurationJob: Job? = null
    private fun startRssiDurationJob() {
        // 如果已有倒计时在运行，则先取消它
        rssiDurationJob?.cancel()
        rssiDurationJob = viewModelScope.launch {
            while (isActive) {
                delay(1000L) // 每秒触发
                val isAgo = System.currentTimeMillis() - testFromTime > _appSettingFlow.value.rssiMins * 60 * 1000
               if (isAgo) {
                   testFromTime = System.currentTimeMillis() - _appSettingFlow.value.rssiMins * 60 * 1000

                   if(!isHistory) fromTime = testFromTime
               }
            }
        }
    }
    init {

        if(!isHistory) fromTime = testFromTime

        _uiDataState.update {
            it.copy(title = "$fromDevId -> $toDevId")
        }
        rssiRepo.observeLastRssi(usbId = usbId).map {
            handleRssiListAsync(it)
        }.catch { emit(Async.Error(R.string.loading_task_error))
        }.map { task ->
            when (task) {
                Async.Loading -> emptyList()
                is Async.Error -> emptyList()
                is Async.Success -> {
                    _rssiList = task.data as MutableList<WsnDeviceRssiDto>
                    _rssiList
                }
            }
        }.stateIn(
            scope = viewModelScope,
            started = Eagerly,
            initialValue =  emptyList()
        )

        prefDataStore.getAppSettings().map { result ->
            _appSettingFlow.update {result}
            startRssiDurationJob()
        }.launchIn(viewModelScope)

        startCountdown()

        startAvgPerJob()

    }

    override fun onCleared() {
        super.onCleared()
        // 在这里执行清理工作
        stopRepeatingSound()
//        appScope.cancel()      // 取消全局作用域  直接调用 appScope.cancel() 确实可能导致一些问题，尤其是当多个组件或模块共享使用这个全局作用域时。
    }

    private fun handleRssiListAsync(task: List<WsnDeviceRssiDto>?): Async<List<WsnDeviceRssiDto>> {
        if (task == null) {
            return Async.Error(R.string.task_not_found)
        }
        return Async.Success(task)
    }

//    private var _rssiCurrentAsync = observeRssiByFromToDev()

//    private fun observeRssiByFromToDev(): Flow<Async<List<WsnDeviceRssiDto>>>{
//        return  rssiRepo.observeRssiByFromToDev(usbId = usbId, fromDevId, toDevId).map {
//            handleRssiCurrentAsync(it)
//        }.catch {
//            emit(Async.Error(R.string.loading_task_error))
//        }
//    }

//    private fun startObserveRssiByFromToDev(): StateFlow<CommonUiState<WsnDeviceRssiDto>>{
//       return _rssiCurrentAsync.map { task ->
//            when (task) {
//                Async.Loading -> CommonUiState(status = UiStatus.Loading)
//                is Async.Error -> CommonUiState(
//                    status = UiStatus.Error,
//                )
//                is Async.Success -> {
//                    _rssiData = task.data as MutableList<WsnDeviceRssiDto>
////                    calcRssiAverages()
//                    CommonUiState(
//                        status = UiStatus.Success,
//                        dataList = task.data
//                    )
//                }
//            }
//        }.stateIn(
//            scope = viewModelScope,
//            started = Eagerly,
//            initialValue = CommonUiState()
//        )
//    }

    private fun handleRssiCurrentAsync(task: List<WsnDeviceRssiDto>?): Async<List<WsnDeviceRssiDto>> {
        if (task == null) {
            return Async.Error(R.string.task_not_found)
        }
        return Async.Success(task)
    }


    private val _restartState = MutableStateFlow(false)
    val restartState: StateFlow<Boolean> = _restartState.asStateFlow()
    fun requestRestart() =  viewModelScope.launch {
        _restartState.update {
            true
        }
    }
    fun cancelRestart()   {
        _restartState.update {
            false
        }
    }
    private var isBackGround: Boolean = false
    fun frontToBack() {
        cancelRestart()
        isBackGround = true
    }
    fun backToFront() {
        if(isBackGround){
            _uiDataState.update {
                it.copy(toastMsgId = R.string.wsn_w_app_test_back_to_front)
            }
            startTest()
            isBackGround = false
        }
    }


    fun startTest() {
        startCountdown()
        testFromTime  = System.currentTimeMillis()
        _perList.clear()
        _perSecs.update { 12.0f }
        _datePerState.value = _perList.toList()
        _dateRssiState.value = emptyList()
        cancelRestart()
    }

    fun saveCurrentTest(projectName: String = ""):WsnTestRecordDto? {
        if(isHistory) return null
        cancelRestart()
         var testRecord:WsnTestRecordDto? = null
         viewModelScope.launch {
               testRecord = testRepo.add("", fromTime, toTime = System.currentTimeMillis(), projectName = projectName, routeName = "${fromDevId}-->${toDevId}").first()
         }
        return testRecord
    }


    fun renameTestRecord(projectName: String): Int? {
        if (projectName == "111111") return null
        saveCurrentTest(projectName = projectName)
        return R.string.task_not_found
    }

    val uiDataState: StateFlow<UiDataState> = _uiDataState.asStateFlow()

//    val rssiCurrentFlow: StateFlow<CommonUiState<WsnDeviceRssiDto>> =  startObserveRssiByFromToDev()

    /**
     * Toast message clear
     *
     */
    fun toastMessageClear(){
        _uiDataState.update {
            it.copy(toastMsgId = null, toastMsgArgs = emptyArray<Any>())
        }
    }

    /**
     * Offset current rssi
     *
     * @param offsetIndex
     */
    fun offsetCurrentRssi(offsetIndex:Int = 1) {
        val idx = _rssiList.indexOfFirst { it.fromDevId == fromDevId && it.toDevId == toDevId }
        if(offsetIndex > 0){
            if(idx + offsetIndex > _rssiList.size - 1){
//                _uiDataState.update {
//                    it.copy(toastMsgId = R.string.wsn_err_already_last)
//                }
                return
            }
        }else if(offsetIndex < 0){
            if(idx + offsetIndex <0){
//                _uiDataState.update {
//                    it.copy(toastMsgId = R.string.wsn_err_already_first)
//                }
                return
            }
        }
        val dto = _rssiList[idx + offsetIndex]
        _uiDataState.update {
            fromDevId = dto.fromDevId
            toDevId = dto.toDevId
            it.copy(title = "$fromDevId -> $toDevId")
        }
//        _rssiCurrentAsync = observeRssiByFromToDev()
//        startObserveRssiByFromToDev()
    }

//
//    private val _avgNum = MutableStateFlow(4)
//    val avgNum: StateFlow<Int> = _avgNum.asStateFlow()
//
//    /**
//     * Set avg num
//     *
//     * @param num
//     */
//    fun setAvgNum(num:Int) {
//        _avgNum.value = num
//        viewModelScope.launch { calcRssiAverages()}
//    }

    private val _dateRssiState = MutableStateFlow<List<Triple<String, Double?, Double?>>>(emptyList())
    val dateRssiState: StateFlow<List<Triple<String, Double?, Double?>>> = _dateRssiState.asStateFlow()

    fun toggleMockMode() {
        FhcFlowEventBus.publish(FlowEventBusData(EventType.ToggleMockJob, null))

    }

    private val _toImageTimeState = MutableStateFlow("")
    val toImageTimeState: StateFlow<String> = _toImageTimeState.asStateFlow()
    fun toImage() {
        _toImageTimeState.value = System.currentTimeMillis().ymdHMS()
    }
    fun createImageExcel(imagePath: String) {
        createExcel(getApplication(), imagePath = imagePath)
    }

    fun sendEmail(activity: Activity, imagePath: String) {
        sendEmailWithAttachment(activity, fileUri = getInternalFileUri(getApplication(), File(imagePath)))
    }



//    fun getInternalFileUri(context: Context, fileName: String): Uri {
//        val file = File(context.filesDir, fileName)
//        return FileProvider.getUriForFile(
//            context,
//            "${context.packageName}.provider",
//            file
//        )
//    }
    fun getInternalFileUri(context: Context, file:File): Uri {
        return FileProvider.getUriForFile(
            context,
            "${context.packageName}.provider",
            file
        )
    }

    fun sendEmailWithAttachment(
        context: Context,
        fileUri: Uri,
        recipient: String = "recipient",
        subject: String = "subject",
        body: String = "body",
    ) {
        val intent = Intent(Intent.ACTION_SEND).apply {
            type = "multipart/mixed" // 或 "text/html" 根据内容决定

            putExtra(Intent.EXTRA_EMAIL, arrayOf(recipient))
            putExtra(Intent.EXTRA_SUBJECT, subject)
            putExtra(Intent.EXTRA_TEXT, Html.fromHtml("<b>${body}</b><font color='red'>红色文字</font>",Html.FROM_HTML_MODE_LEGACY,null,   null   ))
            putExtra(Intent.EXTRA_STREAM, fileUri)
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
//            // 关键修复：添加任务栈标志
//            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        context.startActivity(Intent.createChooser(intent, "发送邮件"))
    }

    private val _datePerState = MutableStateFlow<List<Pair<String, Double>>>(emptyList())
    val datePerState: StateFlow<List<Pair<String, Double>>> = _datePerState.asStateFlow()

    private val _perList  = mutableListOf<Pair<String, Double>>()



    /**
     * Calc rssi averages
     *
     */
    private suspend fun calcRssiAvg() {
        withContext(dispatcher) {
            val data = rssiRepo.getByFromToAndTime(usbId = usbId, fromDevId, toDevId, testFromTime)
            _rssiData.clear()
            _rssiData.addAll(data)

            // 按设备对分组
            val groupedData = _rssiData.groupBy { Pair(it.fromDevId, it.toDevId) }

            if (_rssiData.isEmpty() || groupedData.isEmpty()) return@withContext

            val result: MutableList<Triple<Long, Double?, Double?>> = mutableListOf()
            groupedData.forEach { (_, deviceData) ->
                //deviceData 的_avgNum.value 前几个分别平均固定，后续递进平均，比如 data1;data1,2;data1,2,3;data1,2,3,4;
                if (deviceData.size >= _appSettingFlow.value.avgNums) {
                    for (i in 0.._appSettingFlow.value.avgNums - 1) {
                        val subList = deviceData.subList(0, i)
                        if (subList.isEmpty()) continue
                        val avgRssi = subList.map { it.rssi }.average().minMax(-110.0,-10.0)
                        val lastRssi = subList.last().rssi.toDouble().minMax(-110.0,-10.0)  //最近时间的
                        result.add(Triple(subList.last().dateTime, avgRssi, lastRssi))
                    }

                    // 滑动窗口处理
                    for (i in 0..deviceData.size - _appSettingFlow.value.avgNums) {
                        val subList = deviceData.subList(i, i + _appSettingFlow.value.avgNums)
                        if (subList.isEmpty()) continue
                        val avgRssi = subList.map { it.rssi }.average().minMax(-110.0,-10.0)
                        val lastRssi = subList.last().rssi.toDouble().minMax(-110.0,-10.0)  //最近时间的
                        result.add(Triple(subList.last().dateTime, avgRssi, lastRssi))
                    }
                } else {
//                    // 不足avgNum条数据时计算整体平均
//                    val avgRssi = deviceData.map { it.rssi }.average()
//                    val lastRssi = deviceData.last().rssi.toDouble()
//                    result.add(Triple(deviceData.last().dateTime.takeLast(8) ,avgRssi, lastRssi))
                    // 滑动窗口处理
                    for (i in 0..deviceData.size) {
                        val subList = deviceData.subList(0, i)
                        if (subList.isEmpty()) continue
                        val avgRssi = subList.map { it.rssi }.average().minMax(-110.0,-10.0)
                        val lastRssi = subList.last().rssi.toDouble().minMax(-110.0,-10.0)  //最近时间的
                        result.add(Triple(subList.last().dateTime, avgRssi, lastRssi))
                    }
                }
            }

            // 在设置 _dateRssiState.value 前，检查相邻数据点之间的时间间隔
            // 如果超过4秒，则插入新数据点
            val processedResult = mutableListOf<Triple<String, Double?, Double?>>()
            if (result.isEmpty()) {
                result.add(Triple(System.currentTimeMillis(), null, null))
            }
            for (i in result.indices) {
                // 添加当前数据点
                processedResult.add(Triple(result[i].first.ymdHMS().takeLast(8), result[i].second, result[i].third))

                var currentTime = result[i].first
                val nextTime = if (i < result.size - 1) {
                    result[i + 1].first
                } else {
                    System.currentTimeMillis()
                }
                while (nextTime - currentTime > 4100) {
                    val insertSeconds = currentTime +  4000
                    processedResult.add(Triple(insertSeconds.ymdHMS().takeLast(8), null, null))
                    currentTime= insertSeconds
                }
            }
            Timber.w("calcRssiAverages:   ${processedResult.size}    ${processedResult.get(0).first}   ${processedResult.get(processedResult.size-1).first}")
            _dateRssiState.value = processedResult
        }
    }

    /**
     * Auto calc PER
     *
     */
    private suspend fun calcRssiPer(){
        withContext(dispatcher) {
            val currentMS = System.currentTimeMillis()

            if(_perSecs.value > 0){
                return@withContext
            }
            val filteredList = _rssiData.filter { it.dateTime > testFromTime }
            val receiveCnt = filteredList.size //1) how many RSSI packets the USB dongle gateway received for that route

            val elapsed =  (currentMS - testFromTime) // the elapsed time since the user selects the route.
            val expectCnt = floor(elapsed/(RssiInterval*1.0))
            val psr = receiveCnt.toDouble()/expectCnt
            var per = 1 - psr
            if(per < 0) per = 0.0
            _perList.add(currentMS.ymdHMS().takeLast(8) to per * 100)
            while (_perList.size > (_appSettingFlow.value.rssiMins*60)/(RssiInterval/1000)) {
                _perList.removeAt(0)
            }
            
            _datePerState.value = _perList.toList()
            //            直接修改_perList不会自动触发StateFlow更新
            //            必须通过给_datePerState.value赋新值来触发更新
            //            使用toList()创建新列表实例确保能触发更新

        }
    }

}